using System;
using System.Linq;
using System.Text;
using Bubbles;
using Controls;
using Data;
using Locomotion;
using TMPro;
using UnityEngine;
using UnityEngine.UI;

namespace UI
{
    public class InputBox : MonoBehaviour
    {
        public static event Action<string> ChatMessageSubmitted;

        [SerializeField] private TMP_InputField inputField;
        [SerializeField] private Button buttonSend;
        [SerializeField] private Transform bulletAreaTransform;

        [SerializeField] private Font fontForRandomSelect;
        
        [SerializeField] private MessageSpawner messageSpawner;
        [SerializeField] private CriticalHitController criticalHitController;
        
        private BulletArea _bulletArea;
        private string _randomCharacters;
        private readonly StringBuilder _chaosStringBuilder = new();
        private StringBuilder _fixedStringBuilder = new StringBuilder();


        private void Start()
        {
            _bulletArea = new BulletArea(bulletAreaTransform, criticalHitController);
            InitRandomCharacter();
            ForceFocus();
            buttonSend.onClick.AddListener(OnBtnSendClick);
        }

        private void Update()
        {
            buttonSend.interactable = CanSend();
        }
        
        private void OnEnable()
        {
            MessageSpawner.NextMessageFixed += MessageSpawner_NextMessageFixed;
        }

        private void OnDisable()
        {
            MessageSpawner.NextMessageFixed -= MessageSpawner_NextMessageFixed;
        }

        private void MessageSpawner_NextMessageFixed(FixedBubbleInfo bubbleInfo)
        {
            _fixedStringBuilder.Append(bubbleInfo.content);
        }

        public void OnInputTextChanged()
        {
            ConvertStringToChaos(inputField.text);
        }

        private bool CanSend()
        {
            return inputField.text.Length > 0 && messageSpawner.CanShowMessage();
        }

        private void DoSend()
        {
            if (!CanSend())
            {
                return;
            }
            
            string sendContent = _chaosStringBuilder.ToString();
            messageSpawner.ShowMessage(sendContent);
            ChatMessageSubmitted?.Invoke(sendContent);

            inputField.SetTextWithoutNotify(String.Empty);
            _chaosStringBuilder.Clear();
            _fixedStringBuilder.Clear();
        }
        
        private void OnBtnSendClick()
        {
            DoSend();
        }
        
        private char GetRandomCharacter(int index)
        {
            if (_fixedStringBuilder.Length == 0 || index >= _fixedStringBuilder.Length)
            {
                int randomIndex = UnityEngine.Random.Range(0, _randomCharacters.Length);
                return _randomCharacters[randomIndex];   
            }
            else
            {
                return _fixedStringBuilder[index];
            }
        }

        private void ConvertStringToChaos(string oriStr)
        {
            int lenDiff = oriStr.Length - _chaosStringBuilder.Length;
            if (lenDiff > 0)
            {
                if (_bulletArea.LeftBlockCount == 0 || !CanSend())
                {
                    inputField.SetTextWithoutNotify(_chaosStringBuilder.ToString());
                    return;
                }
                
                for (int i = 0; i < lenDiff; i++)
                {
                    var randomChara = GetRandomCharacter(_chaosStringBuilder.Length);
                    _chaosStringBuilder.Append(randomChara);
                }
            }
            else if (lenDiff < 0)
            {
                int startDeleteIndex = _chaosStringBuilder.Length + lenDiff;
                _chaosStringBuilder.Remove(startDeleteIndex, -lenDiff);
            }
            
            _bulletArea.OnInputFieldChange(lenDiff);
            inputField.SetTextWithoutNotify(_chaosStringBuilder.ToString());
        }
        
        private void InitRandomCharacter()
        {
            int randomCount = fontForRandomSelect.characterInfo.Length;
            // 获取字体中所有的字符
            _randomCharacters = new string(fontForRandomSelect.characterInfo.Select(c => c.index).Select(i => (char) i)
                .ToArray());
        }

        private void ForceFocus()
        {
            inputField.Select();
            inputField.onEndEdit.AddListener(val =>
            {
                CheckKeySend();
                Refocus();
            });
        }
        
        private void CheckKeySend()
        {
            bool isPressSend = Input.GetKeyDown(KeyCode.Return);
            if (isPressSend)
            {
                DoSend();
            }
        }
        
        private void Refocus()
        {
            inputField.Select();
            inputField.ActivateInputField();
        
            inputField.caretPosition = inputField.text.Length;
            inputField.selectionAnchorPosition = inputField.caretPosition;
            inputField.selectionFocusPosition = inputField.caretPosition;
        }
    }
}